package com.foreverwin.jzymes.websocket;

import com.alibaba.fastjson.JSONObject;
import com.foreverwin.jzymes.common.constant.Constants;
import com.foreverwin.jzymes.common.domain.CarrierBind;
import com.foreverwin.jzymes.common.domain.NcData;
import com.foreverwin.jzymes.common.domain.TwoHourYield;
import com.foreverwin.jzymes.common.domain.YieldLog;
import com.foreverwin.jzymes.common.mapper.DashBoardAdviceMapper;
import com.foreverwin.jzymes.common.mapper.NcDataAdviceMapper;
import com.foreverwin.jzymes.common.service.*;
import com.foreverwin.jzymes.framework.event.AppEvent;
import com.foreverwin.jzymes.framework.event.AppEventPublisher;
import com.foreverwin.jzymes.framework.exception.BusinessException;
import com.foreverwin.jzymes.framework.util.DateUtil;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

@Component
public class AppEventHandler {

    @Autowired
    IProductionShiftService productionShiftService;
    @Autowired
    ICarrierBindAdviceService carrierBindAdviceService;
    @Autowired
    IResourceAdviceService resourceAdviceService;
    @Autowired
    IYieldLogService yieldLogService;
    @Autowired
    ISystemRuleAdviceService systemRuleAdviceService;
    @Autowired
    DashBoardAdviceMapper dashBoardAdviceMapper;
    @Autowired
    NcDataAdviceMapper ncDataAdviceMapper;
    @Autowired
    JmsMessagingTemplate jmsTemplate;
    @Autowired
    AppEventPublisher appEventPublisher;

    @EventListener
    public void twoHour( AppEvent appEvent ){
        List events = Arrays.asList( "CARRIER_CHECK_OUT_EVENT", "ITEM_CHECK_OUT_EVENT", "TRAY_CHECK_OUT_EVENT", "CARRIER_NC_CHECK_OUT_EVENT" );
        if( !events.contains( appEvent.getName() ) ) return;
        String event = appEvent.getName();
        JSONObject eventData = (JSONObject) appEvent.getData();

        if( "CARRIER_CHECK_OUT_EVENT".equals( event ) || "CARRIER_NC_CHECK_OUT_EVENT".equals( event ) ) {
            String site = eventData.getString("SITE");
            String carrier = eventData.getString("CARRIER");
            String resrce = eventData.getString("RESRCE");

            String operation = resourceAdviceService.findOperationByResource( site, resrce );

            saveTwoHour( site, operation, null, 1L );
        }else if( "TRAY_CHECK_OUT_EVENT".equals( event ) ) {
            String site = eventData.getString("SITE");
            String resrce = eventData.getString("RESRCE");
            Long qty = eventData.getLong("CARRIER_QTY");

            String operation = resourceAdviceService.findOperationByResource( site, resrce );

            saveTwoHour( site, operation, null, qty );
        }else if( "ITEM_CHECK_OUT_EVENT".equals( event ) ){
            String site = eventData.getString( "SITE" );
            String itemBo = eventData.getString( "ITEM_BO" );
            String resrce = eventData.getString( "RESRCE" );
            Long qty = eventData.getLong( "QTY" );

            String operation = resourceAdviceService.findOperationByResource( site, resrce );

            saveTwoHour( site, operation, itemBo, qty );
        }

        AppEvent<JSONObject> _appEvent = new AppEvent<>( this );
        _appEvent.setName( "TWO_HOUR_CHECK_OUT" );
        ActiveMQTopic topic = new ActiveMQTopic("MES_APP_EVENT_INFRA");
        jmsTemplate.convertAndSend( topic, _appEvent );
    }

    @EventListener
    public void yield( AppEvent appEvent ){
        List events = Arrays.asList( "CARRIER_CHECK_OUT_EVENT", "ITEM_CHECK_OUT_EVENT", "CARRIER_NC_CHECK_OUT_EVENT", "ITEM_NC_SCRAP_EVENT", "ITEM_NC_REWORK_EVENT" );
        if( !events.contains( appEvent.getName() ) ) return;
        String event = appEvent.getName();
        JSONObject eventData = (JSONObject) appEvent.getData();

        if( "CARRIER_CHECK_OUT_EVENT".equals( event ) || "CARRIER_NC_CHECK_OUT_EVENT".equals( event ) ){
            String site = eventData.getString( "SITE" );
            String carrier = eventData.getString( "CARRIER" );
            String resrce = eventData.getString( "RESRCE" );

            String operation = resourceAdviceService.findOperationByResource( site, resrce );
            List<CarrierBind> carrierBindList = carrierBindAdviceService.findCarrierBindOnBind( site, carrier );
            if( carrierBindList.size() == 0 ){
                carrierBindList = carrierBindAdviceService.findCarrierUnbind( site, carrier );
            }

            /**检查本体料件是否存在返工*/
            Map<String,Object> queryParam = new HashMap<>();
            queryParam.put( "site", site );
            queryParam.put( "operation", operation );
            queryParam.put( "carrier", carrier );
            queryParam.put( "isRework", "true" );
            queryParam.put( "fromDate", carrierBindList.get(0).getStartDateTime() );
            List<NcData> reworkNcList = ncDataAdviceMapper.selectNcDataList( queryParam );

            for( CarrierBind carrierBind : carrierBindList ){
                if( reworkNcList.size() > 0 ){
                    saveYieldLog( site, operation, carrierBind.getItemBo(), 0L, 1L, 0L );
                }else{
                    saveYieldLog( site, operation, carrierBind.getItemBo(), 1L, 0L, 0L );
                }
            }

        }else if( "ITEM_CHECK_OUT_EVENT".equals( event ) ){
            String site = eventData.getString( "SITE" );
            String itemBo = eventData.getString( "ITEM_BO" );
            String resrce = eventData.getString( "RESRCE" );
            Long qty = eventData.getLong( "QTY" );

            Date date = new Date();
            String operation = resourceAdviceService.findOperationByResource( site, resrce );

            YieldLog yieldLog = dashBoardAdviceMapper.findYieldLog( site, operation, itemBo, date );
            if( yieldLog != null ){
                yieldLog.setInputQty( yieldLog.getInputQty() + qty );
                yieldLog.setGoodQty( yieldLog.getInputQty() - yieldLog.getReworkQty() - yieldLog.getScrapQty() );
                yieldLog.setFirstTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
                yieldLog.setSecondTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() + yieldLog.getReworkQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
                yieldLogService.updateYieldLog( yieldLog );
            }else{
                Date[] timeRange = computeDateRange( site, date );
                yieldLog = new YieldLog();
                yieldLog.setHandle( UUID.randomUUID().toString() );
                yieldLog.setSite( site );
                yieldLog.setTimeRange( DateUtil.format( timeRange[0], "HH" ) + "-" + DateUtil.format( timeRange[1], "HH" ) );
                yieldLog.setOperation( operation );
                yieldLog.setItemBo( itemBo );
                yieldLog.setInputQty( qty );
                yieldLog.setGoodQty( qty );
                yieldLog.setReworkQty( 0L );
                yieldLog.setFirstTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
                yieldLog.setSecondTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() + yieldLog.getReworkQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
                yieldLog.setStartDateTime( timeRange[0] );
                yieldLog.setEndDateTime( timeRange[1] );
                yieldLogService.insertYieldLog( yieldLog );
            }

        }else if( "ITEM_NC_SCRAP_EVENT".equals( event ) ){
            String site = eventData.getString( "SITE" );
            String itemBo = eventData.getString( "ITEM_BO" );
            String resrce = eventData.getString( "RESRCE" );
            Long qty = eventData.getLong( "QTY" );

            String operation = resourceAdviceService.findOperationByResource( site, resrce );

            saveYieldLog( site, operation, itemBo, 0L, 0L, qty );

        }else if( "ITEM_NC_REWORK_EVENT".equals( event ) ){
            String site = eventData.getString( "SITE" );
            String itemBo = eventData.getString( "ITEM_BO" );
            String resrce = eventData.getString( "RESRCE" );
            Long qty = eventData.getLong( "QTY" );

            String operation = resourceAdviceService.findOperationByResource( site, resrce );

            saveYieldLog( site, operation, itemBo, 0L, qty, 0L );
        }

        AppEvent<JSONObject> _appEvent = new AppEvent<>( this );
        _appEvent.setName( "YIELD_REPORT" );
        ActiveMQTopic topic = new ActiveMQTopic("MES_APP_EVENT_INFRA");
        jmsTemplate.convertAndSend( topic, _appEvent );
    }

    /**
     * 获取当前时间2H区间
     *
     * @return
     */
    public Date[] computeDateRange( String site, Date date ){
        Date[] timeRange = null;
        Date[] dayRange = productionShiftService.findProductionDayRange( site );

        int hourInterval = Integer.valueOf( systemRuleAdviceService.findSystemRule( site, Constants.SYSTEM_RULE_TWO_HOUR, "2" ) );

        for( timeRange = new Date[2]; timeRange[1] == null || timeRange[1].before( date );  ){
            if( timeRange[0] == null ){
                timeRange[0] = dayRange[0];
            }else{
                timeRange[0] = DateUtil.addHours( timeRange[0], hourInterval );
            }
            timeRange[1] = DateUtil.addHours( timeRange[0], hourInterval );
        }

        if( timeRange[0] == null || timeRange[1] == null ){
            throw BusinessException.build( "Time range compute wrong." );
        }
        return timeRange;
    }

    /**
     * 保存两小时数据
     *
     * @param site
     * @param operation
     * @param itemBo
     * @param qty
     */
    public synchronized void saveTwoHour( String site, String operation, String itemBo, Long qty ){
        Date date = new Date();
        TwoHourYield yieldMap = dashBoardAdviceMapper.findTwoHourYield( site, operation, itemBo, date );
        if( yieldMap != null ) {
            TwoHourYield paramMap = new TwoHourYield();
            paramMap.setHandle( yieldMap.getHandle() );
            paramMap.setQty( yieldMap.getQty() + qty );
            dashBoardAdviceMapper.updateTwoHourYield( paramMap );
        }else{
            Date[] timeRange = computeDateRange( site, date );
            yieldMap = new TwoHourYield();
            yieldMap.setHandle( UUID.randomUUID().toString() );
            yieldMap.setSite( site );
            yieldMap.setTimeRange( DateUtil.format( timeRange[0], "HH" ) + "-" + DateUtil.format( timeRange[1], "HH" ) );
            yieldMap.setOperation( operation );
            yieldMap.setItemBo( itemBo );
            yieldMap.setQty( qty );
            yieldMap.setStartDateTime( timeRange[0] );
            yieldMap.setEndDateTime( timeRange[1] );
            dashBoardAdviceMapper.insertTwoHourYield( yieldMap );
        }
    }

    /**
     * 保存良率数据
     *
     * @param site
     * @param operation
     * @param itemBo
     * @param goodQty
     * @param reworkQty
     * @param scrapQty
     */
    public synchronized void saveYieldLog( String site, String operation, String itemBo, Long goodQty, Long reworkQty, Long scrapQty ){
        Date date = new Date();
        YieldLog yieldLog = dashBoardAdviceMapper.findYieldLog( site, operation, itemBo, date );
        if( yieldLog != null ){
            yieldLog.setGoodQty( yieldLog.getGoodQty() + goodQty );
            yieldLog.setReworkQty( yieldLog.getReworkQty() + reworkQty );
            yieldLog.setScrapQty( yieldLog.getScrapQty() + scrapQty );
            yieldLog.setInputQty( yieldLog.getInputQty() + goodQty + reworkQty + scrapQty );
            yieldLog.setFirstTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
            yieldLog.setSecondTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() + yieldLog.getReworkQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
            yieldLogService.updateYieldLog( yieldLog );
        }else{
            Date[] timeRange = computeDateRange( site, date );
            yieldLog = new YieldLog();
            yieldLog.setHandle( UUID.randomUUID().toString() );
            yieldLog.setSite( site );
            yieldLog.setTimeRange( DateUtil.format( timeRange[0], "HH" ) + "-" + DateUtil.format( timeRange[1], "HH" ) );
            yieldLog.setOperation( operation );
            yieldLog.setItemBo( itemBo );
            yieldLog.setGoodQty( goodQty );
            yieldLog.setReworkQty( reworkQty );
            yieldLog.setScrapQty( scrapQty );
            yieldLog.setInputQty( goodQty + reworkQty + scrapQty );
            yieldLog.setFirstTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
            yieldLog.setSecondTimeYield( BigDecimal.valueOf( yieldLog.getGoodQty() + yieldLog.getReworkQty() ).divide( BigDecimal.valueOf( yieldLog.getInputQty() ), 4, BigDecimal.ROUND_HALF_UP ).multiply( BigDecimal.valueOf( 100 ) ) );
            yieldLog.setStartDateTime( timeRange[0] );
            yieldLog.setEndDateTime( timeRange[1] );
            yieldLogService.insertYieldLog( yieldLog );
        }
    }

}
